package mredis

import (
	"time"
	"net"
	"fmt"
	"bufio"
	"strings"
	"errors"
	"log"
)

var (
	MinPoolSize = 10
	MaxPoolSize = 100
	IdleTimeout = 300 * time.Second
)

type RedisClient struct {
	host string
	port int
	timeout int64
	reserved int64
	retryInterval int
	db int
	pool *RedisPool
}

func NewRedisClient(host string, port int, timeout int64,password string) (*RedisClient,error)  {
	r :=  &RedisClient{}

	r.host = host
	r.port = port
	r.timeout = timeout
	r.db = 0

	pool,err := NewRedisPool(MinPoolSize,MaxPoolSize,IdleTimeout, func() (*RedisConn, error) {
		rconn := &RedisConn{ db:0}
		conn,err := net.Dial("tcp",fmt.Sprintf("%s:%d",host,port))
		if err != nil {
			return rconn,err
		}
		if password != ""{
			cmd := fmt.Sprintf("AUTH %s\r\n", password)
			if _,err := conn.Write([]byte(cmd));err != nil {
				return rconn,err
			}
			reader := bufio.NewReader(conn)
			var line string
			var err error

			for {
				line, err = reader.ReadString('\n')
				if len(line) == 0 || err != nil {
					return rconn, err
				}
				line = strings.TrimSpace(line)
				if len(line) > 0 {
					break
				}
			}
			if strings.HasPrefix("-Error",line) {
				return rconn,errors.New(line[6:])
			}
		}

		rconn.conn = conn
		rconn.connTime = time.Now()
		rconn.reader = bufio.NewReader(conn)
		rconn.writer = bufio.NewWriter(conn)
		return rconn,nil
	})
	if err != nil {
		return nil,err
	}

	r.pool = pool

	return r,nil
}

//获取一个可用连接
func (r *RedisClient) getConn() (*RedisConn,error){
	conn,err := r.pool.Acquire()
	if err != nil {
		log.Printf("Get conn error:%s",err)
		return conn,err
	}
	//如果执行过SELECT命令，需要对获取到的连接再次执行此命令
	if conn.db != r.db {
		_,err = conn.WriteString(fmt.Sprintf("SELECT %d\r\n",r.db))
		if err != nil {
			return nil,err
		}
		b,err := conn.ReadAsString()
		if err != nil {
			return nil,err
		}
		if b != "OK" {
			return nil,RedisError("Unexpected response to Select.")
		}
		conn.db = r.db
	}
	return conn,nil
}
func (r *RedisClient) releaseConn(conn *RedisConn)error{
	return r.pool.Release(conn)
}

//获取连接命令对象
func (r *RedisClient) Command() (*Command,error) {
	conn,err := r.getConn()
	if err != nil {
		return nil,err
	}
	command := &Command{}
	command.conn = conn
	command.release = func(){
		r.releaseConn(conn)
		command.conn = nil
	}

	return command,nil
}

func (r *RedisClient) SetConnMaxLifetime(t time.Duration) {
	r.pool.maxLifetime = t
}

func (r *RedisClient)  SetMinOpenConn(n int) {
	r.pool.minOpen = n
}

func (r *RedisClient) SetMaxOpenConn(n int) {
	r.pool.maxOpen = n
}